﻿#region License

// Created by John Batte on 03/22/2012 at 8:07 AM.
// Last code cleanup: 03/22/2012 at 8:07 AM.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Collections.Generic;

namespace BatteCode.Fx.Collections
{
	///<summary>
	///	Provides an equality comparer that uses regular object comparison by default, but can be overridden to use custom comparison and hash code retrieval methods.
	///</summary>
	///<typeparam name="T"> The type being compared. </typeparam>
	public class LambdaEqualityComparer<T> : IEqualityComparer<T>
	{
		private readonly Func<T, T, bool> _comparison;

		private readonly Func<T, int> _hashCreator;

		///<summary>
		///	Initializes a new instance of the <see cref="LambdaEqualityComparer{T}" /> class.
		///</summary>
		///<param name="comparison"> The optional comparison algorithm. </param>
		///<param name="hashCreator"> The optional hash code retrieval algorithm. </param>
		public LambdaEqualityComparer(Func<T, T, bool> comparison = null, Func<T, int> hashCreator = null)
		{
			_comparison = comparison;
			_hashCreator = hashCreator;
		}

		#region IEqualityComparer<T> Members

		/// <summary>
		/// 	Determines whether the specified objects are equal.
		/// </summary>
		/// <returns> <c>true</c> if the specified objects are equal; otherwise, <c>false</c> . </returns>
		/// <param name="x"> The first object of type <typeparamref name="T" /> to compare. </param>
		/// <param name="y"> The second object of type <typeparamref name="T" /> to compare. </param>
		public virtual bool Equals(T x, T y)
		{
			return _comparison == null
			       	? object.Equals(x, y)
			       	: _comparison(x, y);
		}

		/// <summary>
		/// 	Returns a hash code for the specified object.
		/// </summary>
		/// <returns> A hash code for the specified object. </returns>
		/// <param name="obj"> The <see cref="T:System.Object" /> for which a hash code is to be returned. </param>
		/// <exception cref="T:System.NullReferenceException">The type of
		/// 	<paramref name="obj" />
		/// 	is a reference type and
		/// 	<paramref name="obj" />
		/// 	is null.</exception>
		public virtual int GetHashCode(T obj)
		{
			return _hashCreator == null
			       	? obj.GetHashCode()
			       	: _hashCreator(obj);
		}

		#endregion
	}
}